package top.flvio.middleware.config;

import org.apache.ibatis.plugin.Interceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.support.TransactionTemplate;
import top.flvio.middleware.DBRouterConfig;
import top.flvio.middleware.DBRouterJoinPoint;
import top.flvio.middleware.dynamic.DynamicDataSource;
import top.flvio.middleware.dynamic.DynamicMybatisPlugin;
import top.flvio.middleware.strategy.IDBRouterStrategy;
import top.flvio.middleware.strategy.impl.DBRouterStrategyHashCode;
import top.flvio.middleware.util.PropertyUtil;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: 数据源自动配置,数据源配置解析
 * @author: flvio
 * @date: 2025/2/5
 */
@Configuration
public class DataSourceAutoConfig implements EnvironmentAware
{

    /**
     * 数据源配置组
     */
    private Map<String, Map<String,Object>> dataSourceMap = new HashMap<>();

    /**
     * 默认数据源配置
     */
    private Map<String,Object> defaultDataSourceConfig;

    /**
     * 分库数量
     */
    private int dbCount;

    /**
     * 分表数量
     */
    private int tbCount;

    /**
     * 路由字段
     */
    private String routerKey;

    @Bean(name = "db-router-point")
    @ConditionalOnMissingBean
    public DBRouterJoinPoint point(DBRouterConfig dbRouterConfig, IDBRouterStrategy dbRouterStrategy){
        return new DBRouterJoinPoint(dbRouterConfig,dbRouterStrategy);
    }

    @Bean
    public DBRouterConfig dbRouterConfig(){
        return new DBRouterConfig(dbCount,tbCount,routerKey);
    }

    @Bean
    public Interceptor plugin(){
        return new DynamicMybatisPlugin();
    }

    @Bean
    public DataSource dataSource(){
        //创建数据源
        Map<Object,Object> targetDataSources = new HashMap<>();
        for(String dbInfo : dataSourceMap.keySet()){
            Map<String,Object> objMap =  dataSourceMap.get(dbInfo);
            targetDataSources.put(dbInfo,new DriverManagerDataSource(objMap.get("url").toString(),
                                                                     objMap.get("username").toString(),
                                                                     objMap.get("password").toString()));
        }

        //设置数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(new DriverManagerDataSource(defaultDataSourceConfig.get("url").toString(),
                                                                                 defaultDataSourceConfig.get("username").toString(),
                                                                                 defaultDataSourceConfig.get("password").toString()));
        return dynamicDataSource;
    }

    @Bean
    public IDBRouterStrategy idbRouterStrategy(DBRouterConfig dbRouterConfig){
        return new DBRouterStrategyHashCode(dbRouterConfig);
    }

    @Bean
    public TransactionTemplate transactionTemplate(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);

        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(dataSourceTransactionManager);
        transactionTemplate.setPropagationBehaviorName("PROPAGATION_REQUIRED");
        return transactionTemplate;
    }

    @Override
    public void setEnvironment(Environment environment)
    {
        String prefix = "mini-db-router.jdbc.datasource.";

        dbCount = Integer.valueOf(environment.getProperty(prefix + "dbCount"));
        tbCount = Integer.valueOf(environment.getProperty(prefix + "tbCount"));
        routerKey = environment.getProperty(prefix + "routerKey");

        //分库分表数据源
        String dataSource = environment.getProperty(prefix + "list");
        assert dataSource != null;
        for(String dbInfo : dataSource.split(",")){
            Map<String,Object> dataSourceProps = PropertyUtil.handle(environment,prefix + dbInfo, Map.class);
            dataSourceMap.put(dbInfo,dataSourceProps);
        }

        // 默认数据源
        String defaultData = environment.getProperty(prefix + "default");
        defaultDataSourceConfig = PropertyUtil.handle(environment,prefix + defaultData,Map.class);
    }
}
